home *** CD-ROM | disk | FTP | other *** search
- /*
- * BSL.C
- *
- * Functions to manipulate the Bad Sector List.
- *
- * 25-Nov-87 ml. Started this mess.
- * 04-Dec-87 ml. Hmmm, looks OK.
- * 11-Dec-87 ml. Added bsl2fat().
- * 14-Dec-87 ml. Structure of BSL is changed (_again_!).
- * Now, first entry in BSL contains number VENDOR
- * entries. First byte of 2nd entry is the checksum
- * byte, while 2nd and 3rd bytes are reserved for
- * future use.
- * 08-Nov-87 jye. change or add codes so that can be used for MS-DOS
- *
- */
-
- #include "obdefs.h"
- #include "osbind.h"
- #include "mydefs.h"
- #include "part.h"
- #include "bsl.h"
- #include "hdx.h"
- #include "addr.h"
- #include "error.h"
-
- /* Globals */
- BYTE *bsl; /* bad sector list */
- long bslsiz; /* num sectors BSL occupies */
- SECTOR badbuf[WARNBADSECTS]; /* bad sectors buffer */
- extern int tformat; /* 1: called by Format */
-
-
- /*
- * Get size of the Bad Sector List (in sectors)
- * Input:
- * pdev - physical unit BSL belongs to.
- * Return:
- * number of sectors BSL occupies.
- */
- long
- gbslsiz(pdev)
- int pdev; /* physical device number */
- {
- char bs[512]; /* boot sector image */
- UWORD ret;
-
- if ((ret = getroot(pdev, bs, (SECTOR)0)) != 0) {
- if (tsterr(ret) == OK)
- return MDMERR;
- else return ERROR;
- }
- if (((RSECT *)(bs + 0x200 - sizeof(RSECT)))->bsl_st != STBSL)
- return 0L;
- return(((RSECT *)(bs + 0x200 - sizeof(RSECT)))->bsl_cnt);
- }
-
-
- /*
- * Set BSL parameters (starting sector and size of BSL) into
- * root sector image.
- * Input:
- * image - root sector image.
- */
-
- sbslparm(image)
- char *image;
- {
- ((RSECT *)(image + 0x200 - sizeof(RSECT)))->bsl_st = STBSL;
- ((RSECT *)(image + 0x200 - sizeof(RSECT)))->bsl_cnt = bslsiz;
- }
-
-
- /*
- * Create a BSL in memory.
- * Input:
- * pdev - physical unit BSL will belong to.
- * type - kind of BSL to be created. NEW or EXPAND.
- * nents - number of VENDOR entries BSL should hold.
- * Output:
- * bsl - pointer to the BSL. (in bsl.h)
- * Return:
- * OK - everything is fine.
- * ERROR - anything is wrong.
- * Comment:
- * "NEW" means to create a totally new BSL.
- * "EXPAND" means to expand an existing BSL.
- */
- creabsl(pdev, type, nents)
- int pdev; /* physical unit number */
- int type; /* kind of BSL to be created */
- long nents; /* num VENDOR entries in BSL */
- {
- BYTE *newbsl; /* BSL just created */
- long l, size; /* l - index into BSL; size - size of BSL in bytes */
- long start; /* where to start initializing entries to zeroes */
- long nument();
-
- if (nents == 0) { /* no VENDOR entries specified */
- size = 512L; /* default size of BSL to 1 sector */
- } else { /* num VENDOR entries is specified */
- /*------------------------------------------------------*/
- /* Calculate length of BSL in bytes. */
- /* Have to add space for reserved entries and USER list */
- /* (note: (+1) to round up) */
- /*------------------------------------------------------*/
- size = (((nents + RENT + WARNBADSECTS)/EPS) + 1) * 512L;
- }
-
- /* allocate enough memory for new BSL */
- if ((newbsl = (BYTE *)mymalloc((int)size)) <= 0)
- return err(nomemory);
-
- if (type == NEW) { /* a new BSL */
- start = 0; /* start at 0th entry, i.e. init whole BSL to 0s */
- }
- else { /* expand the BSL */
- /* start init to 0s after VENDOR list */
- start = (nument(VENDOR) + RENT) * BPE;
-
- /* copy original BSL into this expanded memory */
- for (l = 0; l < start; l++)
- newbsl[l] = bsl[l];
- }
-
-
- /* free up old BSL */
- if (bsl > 0) free(bsl);
- bsl = newbsl;
-
- /* init BSL to zeroes beginning at 'start'th entry */
- for (l = start; l < size; l++)
- bsl[l] = 0;
-
- /* install BSL info */
- bslsiz = size/512; /* current num sectors BSL occupies */
- put3bytes(bsl, nents); /* num VENDOR entries */
- mkmagic(); /* make the BSL checks sum to BSLMAGIC byte-wise */
-
- return OK;
- }
-
-
- /*
- * Read the BSL into memory.
- * Input:
- * pdev - physical unit that contains the BSL.
- * Output:
- * bsl - pointer to the BSL. (in bsl.h)
- * Return:
- * OK - everything is fine.
- * INVALID - BSL doesn't checksum correctly.
- * ERROR - can't read BSL.
- */
- rdbsl(pdev)
- int pdev; /* physical unit to read from */
- {
- int ret;
-
- if ((ret = rdsects(pdev, (UWORD)bslsiz, bsl, (SECTOR)STBSL)) != 0) {
- if (tsterr(ret) != OK) {
- if (tformat == FALSE)
- err(bslread);
- }
- return ERROR;
- }
-
- return(sumbsl()); /* Checksum BSL and return */
- }
-
-
- /*
- * Count number of entries in the requested portion of BSL.
- * Input:
- * portion - portion of BSL. MEDIA, VENDOR, USER or UNUSED.
- * Return:
- * Number of entries of the requested portion.
- * Comments:
- * There are 3 bytes per entry (BPE), and the first 2 entries
- * are reserved (RENT) for BSL info.
- */
- long
- nument(portion)
- int portion; /* portion of BSL to be counted */
- {
- long vdr, usr; /* num ent in VENDOR list, num ent in USER list */
- long nbytes, offset; /* BSL's len in bytes, index into BSL */
- long get3bytes();
-
- /* 2nd entry in BSL contains num entries in VENDOR list */
- vdr = get3bytes(bsl);
-
- if (portion == VENDOR) return (vdr);
-
- nbytes = bslsiz*512; /* num bytes in BSL */
-
- /* num bytes available for valid entries */
- /* (need this because nbytes may not be divisible by BPE) */
- nbytes -= (nbytes % BPE);
-
- /* find out num entries in USER list */
- usr = 0;
- for (offset = (RENT+vdr)*BPE; /* index into beginning of USER list */
- (offset < nbytes) /* while not at end of BSL */
- && get3bytes(bsl+offset); /* and it's a used entry */
- offset += BPE) /* increment index */
- usr++; /* increment num entries for USER list */
-
- if (portion == USER)
- return (usr); /* num entries in USER list */
-
- if (portion == MEDIA)
- return (vdr+usr); /* num entries in MEDIA list */
-
- /* portion == UNUSED */
- return ((nbytes/BPE)-RENT-vdr-usr);
- }
-
-
- /*
- * Write the BSL into the disk.
- * Input:
- * pdev - physical unit number BSL belongs to.
- * bsl - pointer to buffer containing the BSL. (in bsl.h)
- * Return:
- * OK - everything is fine.
- * ERROR - can't write BSL.
- */
- wrbsl(pdev)
- int pdev; /* physical unit number */
- {
- int ret; /* return code */
-
- *((int *)(bsl + 0x4)) = 0; /* set the 4th & 5th byte to 0 in BSL */
- mkmagic();
- if ((ret = wrsects(pdev, (UWORD)bslsiz, bsl, (SECTOR)STBSL)) != 0) {
- if (tsterr(ret) != OK)
- err(bslwrite);
- return ERROR;
- }
-
- return OK;
- }
-
-
- /*
- * Sort the BSL in memory in ascending order.
- * Input:
- * entries - number of used entries in BSL
- * bsl - pointer to the BSL. (in bsl.h)
- * Output:
- * a sorted bsl.
- * Algorithm:
- * Bubble sort.
- * Comments:
- * The reserved entries won't be sorted.
- */
- sortbsl(entries)
- long entries; /* num entries in BSL */
- {
- long i, e1, e2;
- long start; /* beginning byte of entries in BSL */
- long end; /* tail byte of BSL */
- int change; /* signal if changes have been made in current pass */
- long get3bytes();
-
- if (entries == 0L || entries == 1L) /* BSL is empty */
- return;
-
- change = 1; /* assume list is not in order */
- start = RENT*BPE; /* beginning of entries in BSL */
- end = entries * BPE;
- while (1) {
- if (change == 0) /* if no changes made, DONE --> HOME */
- return;
-
- change = 0; /* assume list is in order */
- for (i = start; i <= end; i += BPE) {
- e1 = get3bytes(bsl+i);
- e2 = get3bytes(bsl+i+BPE);
- if (e1 > e2) { /* switch if out of order */
- put3bytes(bsl+i, e2);
- put3bytes(bsl+i+BPE, e1);
- change = 1;
- }
- }
- end -= BPE;
- }
- }
-
-
- /*
- * Search through a sorted BSL for a given sector number.
- * Input:
- * sect - sector number searching for.
- * entries - number of used entries in the BSL.
- * Return:
- * YES - if given sector is found.
- * NO - if given sector is not found.
- * Algorithm:
- * Binary Search.
- */
- srchbsl(sect, entries)
- SECTOR sect; /* sector searching for */
- long entries; /* num used entries in BSL */
- {
- long start, mid, end; /* start, middle and end indices into list */
- SECTOR temp; /* sector number in middle of list */
- long get3bytes();
-
- start = RENT; /* start after reserved entries */
- end = entries+RENT-1; /* end of BSL */
-
- while (1) {
- mid = (start + end) / 2; /* middle entry in list */
- temp = get3bytes(bsl+(mid*BPE)); /* sector num at mid entry */
-
- if (sect == temp) /* given sector == sector at mid entry */
- return YES; /* given sector found in list */
- else if (sect < temp) /* given sector < sector at mid entry */
- end = mid - 1; /* limit search to smaller sector num */
- else /* given sector > sector at mid entry */
- start = mid + 1; /* limit search to larger sector num */
-
- if (end < start) /* list is exhausted */
- return NO; /* can't find given sector */
- }
- }
-
-
- /*
- * Checksum (byte-wise) the BSL.
- * Input:
- * bsl - pointer to the BSL. (in bsl.h)
- * Return:
- * OK - BSL checksum to BSLMAGIC (0xa5).
- * INVALID - BSL does not checksum to BSLMAGIC.
- */
- sumbsl()
- {
- register BYTE sum; /* byte-wise sum of BSL */
- long i; /* index into BSL */
- long length; /* length of BSL in bytes */
-
- length = bslsiz*512; /* length of entire BSL */
- sum = 0; /* initialize the sum */
-
- /* Sum up values in the BSL by byte */
- for (i = 0; i < length; i++) {
- sum += bsl[i];
- }
- if (sum != BSLMAGIC) { /* doesn't checksum correctly */
- return INVALID;
- }
- return OK; /* checksum correctly */
- }
-
-
- /*
- * Make the BSL checks sum to BSLMAGIC.
- */
- mkmagic()
- {
- register BYTE diff; /* difference to make BSL checks sum correctly */
- long i; /* index into BSL */
- long len; /* length of BSL in bytes */
-
- len = bslsiz*512; /* length of entire BSl */
- diff = BSLMAGIC; /* initialize the difference */
-
- /* find out what number would make BSL checks sum to BSLMAGIC */
- for (i = 0; i < len; i++) {
- diff -= bsl[i];
- }
-
- /* add that difference to checksum byte (1st byte of 2nd entry of BSL) */
- bsl[BPE] += diff;
- }
-
-
- /*
- * Add bad sectors found to the Bad Sector List.
- * Input:
- * pdev - physical unit BSL belongs to.
- * portion - portion of BSL to add to. VENDOR or USER.
- * nbad - number of bad sectors to be added.
- * Return:
- * toadd - number of new bad sectors added to the BSL.
- * USRFULL - user part of the BSL is filled up.
- * NOMEM - not enough memory for add buffer or BSL.
- * ERROR - something is wrong.
- * Comment:
- * The entry will be added only if it is not already on the
- * bad sector list. Binary search is performed to guarantee this.
- * If the VENDOR list is full, this routine will take care
- * of the expansion of the list also.
- */
- addbsl(pdev, portion, nbad)
- int pdev; /* physical unit number */
- int portion; /* portion of BSL */
- int nbad; /* num of bad sectors to be added */
- {
- long entries; /* num entries to be retained in BSL */
- long empty; /* num empty slots available for adding entries */
- long end; /* address of end of BSL */
- int i, toadd; /* index to badbuf, num of bad sectors to be added */
- int ret = 0; /* return code */
- SECTOR *addbuf; /* bad sectors to be added to BSL */
- long nument();
-
- /* Allocate memory for sector numbers of bad sectors to be added */
- if ((addbuf = (SECTOR *)mymalloc(nbad*4)) <= 0) {
- err(nomemory);
- return NOMEM;
- }
-
- if (portion == VENDOR) { /* adding to VENDOR list */
- entries = nument(VENDOR); /* only keep the VENDOR list */
- empty = 0; /* there's no unused slot for VENDOR ent */
- } else { /* adding to USER list */
- entries = nument(MEDIA); /* keep entire list */
- empty = nument(UNUSED); /* slots left unused */
- }
- sortbsl(entries); /* sort BSL in ascending order */
- toadd = 0; /* none is to be added to BSL yet */
-
- /* For all bad sectors found, search for them in the current BSL.
- Add them to the list only when they are not already recorded. */
- if (entries) { /* only search if BSL is not empty */
- for (i = 0; i < nbad; i++) {
- if (srchbsl(badbuf[i], entries) == NO) {
- addbuf[toadd] = badbuf[i];
- toadd++;
- }
- }
- } else { /* add in all bad sectors found */
- for (i = 0; i < nbad; i++)
- addbuf[i] = badbuf[i];
- toadd = nbad;
- }
-
- /* All bad sectors found have been recorded. Nothing is added to BSL */
- if (toadd == 0) {
- if (portion == USER && (ret = rdbsl(pdev)) != OK) {
- if (ret == INVALID)
- err(cruptbsl);
- goto togo;
- }
- ret = toadd;
- }
-
- /*------------------------------------------------------------------*/
- /* Check if there are enough empty slots for new entries. If not, */
- /* determine what kind of entries we are adding, VENDOR or USER. */
- /* Expand the BSL if we are adding to VENDOR list. Give warning */
- /* if we are adding to USER list. */
- /*------------------------------------------------------------------*/
- if (toadd > empty) {
- if (portion == VENDOR) { /* this only happens at format time */
- /* expanded BSL should hold (entries + toadd) VENDOR entries */
- if (creabsl(pdev, EXPAND, entries+toadd) != OK)
- goto togo;
- } else { /* We are adding to USER list */
- err(manybad);
- toadd = empty; /* num ent to add = empty slots available */
- }
- }
-
- /* Read in orig unsorted list if adding USER entries */
- if (portion == USER) {
- if ((ret = rdbsl(pdev)) != OK) {
- if (ret == INVALID)
- err(cruptbsl);
- goto togo;
- }
- }
-
- /* Append new entries to end of BSL */
- end = bsl + (RENT + entries)*BPE; /* end of BSL */
- for (i = 0; i < toadd; i++) {
- put3bytes((end + i*BPE), addbuf[i]);
- }
-
- /* make BSL checks sum to magic number */
- mkmagic();
-
- if (portion == USER && toadd == empty) {
- ret = USRFULL;
- goto togo;
- }
-
- ret = toadd;
-
- togo:
- if (addbuf > 0) free(addbuf);
- return(ret);
- }
-
-
- /*
- * Mark bad sectors from the BSL to FATs of a partition.
- * Input:
- * ldev - logical device the FATs belong to.
- * fat0 - logical sector number of where FAT 0 starts.
- * fatsiz - size of FAT in sectors.
- * data - logical sector number of where data clusters start.
- * portion - part of BSL to mark from.
- */
- bsl2fat(ldev, fat0, fatsiz, data, portion)
- int ldev; /* logical device number */
- SECTOR fat0; /* starting sector number (logical) of FAT 0 */
- UWORD fatsiz; /* FAT size */
- SECTOR data; /* starting sector number (logical) of data clusters */
- int portion; /* part of BSL to mark from, VENDOR or MEDIA */
- {
- long nument(), entries; /* num entries in the list to be considered */
- long i, end; /* indices to the list to be considered */
- long get3bytes();
- SECTOR badsect; /* a bad sector in the list */
- SECTOR pstart; /* phys sector num where partition starts */
- SECTOR pdata; /* phys sector num where data block starts */
- SECTOR pend; /* phys sector num where data block ends */
- SECTOR logstart(), logend();
- int nbad;
-
- nbad = 0; /* assume none to be marked */
- pstart = logstart(ldev); /* find where partition starts */
- pdata = pstart + data; /* find where data block starts */
- pend = logend(ldev); /* find where data block ends */
- entries = nument(portion); /* find num entries in given portion */
- sortbsl(entries); /* sort given portion of BSL */
-
- end = (RENT + entries) * BPE;
-
- /* Store vendor bad sectors of the logical device in badbuf */
- for (i = BPE*RENT; i < end; i += BPE) {
- if ((badsect = get3bytes(bsl+i)) > pend)
- break;
-
- if (badsect >= pdata) {
- badbuf[nbad++] = badsect;
-
- /* if badbuf overflows, mark what we have so far in the FAT */
- if (nbad == WARNBADSECTS) {
- if (fixbadcls(ldev, fat0, fatsiz, data, nbad) < 0) {
- return ERROR;
- }
- nbad = 0; /* reinit num bad sectors in partition to 0 */
- }
- }
- }
-
- /* Bad sectors in partition not marked in FAT yet */
- if (nbad) {
- if (fixbadcls(ldev, fat0, fatsiz, data, nbad) < 0) {
- return ERROR;
- }
- }
-
- return OK;
- }
-
-
- /*
- * Count number of bad sectors on a logical drive recorded in BSL.
- * Input:
- * ldev - logical drive to be considered.
- * Return:
- * nbad - number of bad sectors found.
- */
- long
- cntbad(ldev)
- int ldev; /* logical drive number */
- {
- SECTOR pstart, pend; /* phys starting and ending block of ldev */
- extern SECTOR logstart(), logend();
- long nbad=0L; /* num bad sectors on ldev */
- long entries, nument(), bslend;
- long curr, get3bytes();
- int done, i;
-
- pstart = logstart(ldev); /* starting block # of partition */
- pend = logend(ldev); /* ending block # of partition */
- entries = nument(MEDIA); /* num entries in BSL */
- sortbsl(entries); /* sort BSL */
-
- done = 0;
- bslend = (RENT+entries) * BPE;
- for (i = RENT*BPE; (!done) && (i < bslend); i += BPE) {
- curr = get3bytes(bsl+i); /* get next entry in BSL */
- if (curr < pstart) /* not within logical drive's range yet */
- continue;
- if (curr <= pend) /* within logical drive's range */
- nbad++;
- else done = 1; /* pass logical drive's range */
- }
- return (nbad);
- }
-
-
- /*
- * Put a word into memory in 68000 format.
- * Input:
- * p - pointer to memory.
- * i - word to be put.
- */
- putword(p, i)
- BYTE *p;
- UWORD i;
- {
- *p = i >> 8;
- *(p+1) = i;
- }
-
-
- /*
- * Get a 68000 format word from memory.
- * Input:
- * p - pointer to memory.
- * Return:
- * i - word read from memory.
- */
- getword(p)
- BYTE *p;
- {
- UWORD i;
-
- i = *p;
- i <<= 8;
- i |= *(p+1);
- return (i);
- }
-
-
- /*
- * Put 3 bytes (68000 format) into memory.
- * Input:
- * p - pointer to memory.
- * l - long which contains the 3 bytes at the low-bit end.
- */
- put3bytes(p, l)
- BYTE *p;
- long l;
- {
- *p = l >> 16;
- *(p+1) = l >> 8;
- *(p+2) = l;
- }
-
-
- /*
- * Get 3 bytes (68000 format) from memory.
- * Input:
- * p - pointer to memory.
- * Return:
- * l - a long which contains the 3 bytes read in last 3 bytes.
- */
- long
- get3bytes(p)
- BYTE *p;
- {
- long k=0x000000ff, l=0x000000ff;
-
- l &= *p; /* first byte */
- l <<= 16;
- k &= *(p+1); /* second byte */
- k <<= 8;
- l |= k;
- k = 0x000000ff;
- k &= *(p+2); /* third byte */
- l |= k;
- return (l);
- }
-